﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;
using RPGXEngine.Server;
using RPGXEngine.Server.ActionMessages;

namespace RPGX.ServerAdmin.Server
{
    public class Server
    {
        #region Properties

        private object Lock = new object();

        public ServerStatus Status
        {
            get
            {
                return this._status;
            }
            private set
            {
                lock (this.Lock)
                {
                    this._status = value;
                }
            }
        }
        private ServerStatus _status = ServerStatus.Stopped;

        public DateTime StartTime
        {
            get { return _startTime; }
            set { _startTime = value; }
        }
        private DateTime _startTime = DateTime.MinValue;

        public TimeSpan UpTime
        {
            get
            {
                return DateTime.Now - this.StartTime;
            }
        }

        #endregion

        #region Public Methods

        public bool Init()
        {
            this.UpdateStatus();

            return true;
        }

        public bool Start()
        {
            this.Status = ServerStatus.Starting;

            Thread t = new Thread(new ThreadStart(this.StartServerProcess));
            t.Start();

            this.StartTime = DateTime.Now;

            return true;
        }

        public bool Stop()
        {
            this.Status = ServerStatus.Stopping;

            Thread t = new Thread(new ThreadStart(this.StopServerProcess));
            t.Start();

            return true;
        }

        public bool Restart()
        {
            this.Status = ServerStatus.Restarting;

            Thread t = new Thread(new ThreadStart(this.RestartServerProcess));
            t.Start();

            this.StartTime = DateTime.Now;

            return true;
        }

        public bool Pause()
        {
            if (this.Status == ServerStatus.Pausing ||
                this.Status == ServerStatus.Paused)
            {
                this.Status = ServerStatus.Resuming;

                Thread t = new Thread(new ThreadStart(this.ResumeServerProcess));
                t.Start();
            }
            else
            {
                this.Status = ServerStatus.Pausing;

                Thread t = new Thread(new ThreadStart(this.PauseServerProcess));
                t.Start();
            }

            return true;
        }

        #endregion

        #region Private Methods

        private void UpdateStatus()
        {
            Process p = this.GetServerProcess();

            if (p == null)
            {
                this.Status = ServerStatus.Stopped;
            }
            else
            {
                this.Status = ServerRepository.GetCurrentServerStatus();
            }
        }

        private Process GetServerProcess()
        {
            Process[] ps = Process.GetProcessesByName(Configuration.GetServerExeName().Replace(".exe", String.Empty));

            return ps.Length == 0 ? null : ps[0];
        }

        private void StartServerProcess()
        {
            ProcessStartInfo psi = new ProcessStartInfo();
            psi.FileName = String.Format("{0}{1}", Configuration.GetServerExePath(), Configuration.GetServerExeName());
            psi.Arguments = Configuration.GetServerExeArguments();

            Process p = Process.Start(psi);

            this.Status = ServerStatus.Started;
        }

        private void StopServerProcess()
        {
            int messageId = ServerRepository.PostActionMessage(new ServerActionMessage_Stop());

            while (true)
            {
                bool actioned = ServerRepository.HasActionMessageBeenActioned(messageId);
                if (actioned)
                    break;
            }

            Process p = this.GetServerProcess();
            p.Kill();

            this.Status = ServerStatus.Stopped;
        }

        private void RestartServerProcess()
        {
            int messageId = ServerRepository.PostActionMessage(new ServerActionMessage_Restart());

            while (true)
            {
                bool actioned = ServerRepository.HasActionMessageBeenActioned(messageId);
                if (actioned)
                    break;
            }

            this.Status = ServerStatus.Started;
        }

        private void PauseServerProcess()
        {
            int messageId = ServerRepository.PostActionMessage(new ServerActionMessage_Pause());

            while (true)
            {
                bool actioned = ServerRepository.HasActionMessageBeenActioned(messageId);
                if (actioned)
                    break;
            }

            this.Status = ServerStatus.Paused;
        }

        private void ResumeServerProcess()
        {
            int messageId = ServerRepository.PostActionMessage(new ServerActionMessage_Resume());

            while (true)
            {
                bool actioned = ServerRepository.HasActionMessageBeenActioned(messageId);
                if (actioned)
                    break;
            }

            this.Status = ServerStatus.Started;
        }

        #endregion
    }
}
